﻿using System;
using System.Collections.Generic;
using System.Linq.Expressions;
using System.Runtime.Remoting.Messaging;
using System.Threading;
using System.Web;
using Common.Logging;

using Microsoft.Practices.Unity;
using Microsoft.Practices.Unity.Configuration;
using TSharp.Core.Aop;
using TSharp.Core.Asm;

namespace System
{
    /// <summary>
    /// AOP容器上下文
    /// <para>by tangjingbo at 2009-11-4 14:37</para>
    /// </summary>
    public abstract class AopContext : IDisposable
    {
        private static readonly IList<IContainerListener> listeners = new List<IContainerListener>
                                                                          {
                                                                              new LateBindConfiguration()
                                                                          };

        private static Func<HttpContextBase> _factory = () =>
                                                            {
                                                                if (HttpContext.Current != null)
                                                                    return new HttpContextWrapper(HttpContext.Current);
                                                                return null;
                                                            };

        private static AopContext _ctx;
        private readonly ILog log = LogManager.GetLogger("AopContext");
        private UnityConfigurationSection _unitySection;

        #region 常量

        /// <summary>
        /// 系统容器key
        /// </summary>
        private const string CACHEKEY_SYSTEM_CONTAINER = "CONTAINER_SYSTEM";

        /// <summary>
        /// 会话容器KEY
        /// </summary>
        private const string CACHEKEY_SESSION_CONTAINER = "CONTAINER_SESSION";

        /// <summary>
        /// 请求容器key
        /// </summary>
        private const string CACHEKEY_REQUSET_CONTAINER = "CONTAINER_REQUEST";

        private const int millisecondsTimeout = 60000;

        /// <summary>
        /// 系统级别容器名称
        /// </summary>
        public static string CONFIG_CONTAINER_NAME_SYSTEM = "system";

        /// <summary>
        /// 会话级别容器名称
        /// </summary>
        public static string CONFIG_CONTAINER_NAME_SESSION = "session";

        /// <summary>
        /// 请求级别容器名称
        /// </summary>
        public static string CONFIG_CONTAINER_NAME_REQUEST = "request";

        #endregion

        /// <summary>
        /// 
        /// <para>by tangjingbo at 2009-10-22 17:48</para>
        /// </summary>
        private AopContext()
        {
        }

        #region 获取和重新创建上下文

        private static readonly object aopCtxLocker = new object();

        /// <summary>
        /// aop上下文
        /// </summary>
        public static AopContext Current
        {
            get
            {
                if (_ctx != null)
                    return _ctx;
                lock (aopCtxLocker)
                {
                    if (_ctx == null)
                        _ctx = new WebAopContext();

                }
                return _ctx;
            }
        }

        /// <summary>
        /// 重新创建上下文，返回原有上下文
        /// </summary>
        /// <returns></returns>
        public static AopContext Reset()
        {
            AopContext origin = _ctx;

            _ctx = new WebAopContext();

            return origin;
        }

        #endregion

        /// <summary>
        /// 获取默认IOC容器
        /// <para>
        /// TODO:根据配置获取默认level容器
        /// </para>
        /// </summary>
        /// <value>The default.</value>
        public static IUnityContainer Default
        {
            get { return Current.Request; }
        }

        /// <summary>
        /// 获取aopcontext中的HttpContextBase
        /// </summary>
        /// <value>The context.</value>
        public static HttpContextBase Context
        {
            get { return _factory(); }
        }

        /// <summary>
        /// unity配置节点
        /// <para>by tangjingbo at 2009-11-4 14:38</para>
        /// </summary>
        /// <value></value>
        internal UnityConfigurationSection UnitySection
        {
            get
            {
                if (_unitySection != null)
                {
                    return _unitySection;
                }
                _unitySection = WebConfigUtil.GetSection<UnityConfigurationSection>("unity");
                return _unitySection;
            }
        }

        #region RootContainer

        /// <summary>
        /// 系统级别容器.web程序存储在HttpAppliction中，应用程序域内多线程共享
        /// <para>by tangjingbo at 2009-11-4 14:37</para>
        /// </summary>
        /// <value></value>
        public abstract IUnityContainer Root { get; }

        #endregion

        #region SessionContainer

        /// <summary>
        /// 会话级别容器。winform对每个线程会有不同的实例，线程内共享，web中session内共享。
        /// </summary>
        /// <value>The session.</value>
        public abstract IUnityContainer Session { get; }

        #endregion

        #region RequestContainer

        /// <summary>
        /// 请求级别容器。winform首先Session子容器，然后返回；web中每次请求有不同实例，请求内共享。
        /// </summary>
        /// <value>The request.</value>
        public abstract IUnityContainer Request { get; }

        #endregion

        /// <summary>
        /// 设置HTTP上下文工厂.
        /// </summary>
        /// <param name="factory">The factory.</param>
        public static void SetHttpContextFactory(Expression<Func<HttpContextBase>> factory)
        {
            _factory = factory.Compile();
            Reset();
        }

        internal IUnityContainer CreateRoot()
        {
            log.Debug("创建 Root");
            UnityContainerElement containerElement = UnitySection.Containers[CONFIG_CONTAINER_NAME_SYSTEM] ??
                                                     UnitySection.Containers.Default;
            var container = new UnityContainer();
            if (containerElement != null)
                containerElement.Configure(container);
            ServiceManager.RootMap.Configure(container);
            return container;
        }

        internal IUnityContainer CreateSession()
        {
            log.Debug("创建 Session");
            UnityContainerElement containerElement = UnitySection.Containers[CONFIG_CONTAINER_NAME_SESSION];
            IUnityContainer container = Root.CreateChildContainer();
            if (containerElement != null)
                containerElement.Configure(container);
            ServiceManager.SessionMap.Configure(container);
            return container;
        }

        internal IUnityContainer CreateRequest()
        {
            log.Debug("创建 Request");
            UnityContainerElement containerElement = UnitySection.Containers[CONFIG_CONTAINER_NAME_REQUEST];
            IUnityContainer container = Session.CreateChildContainer();
            if (containerElement != null)
                containerElement.Configure(container);
            ServiceManager.RequsetMap.Configure(container);
            return container;
        }

        #region web程序

        private class WebAopContext : AopContext
        {
            public override IUnityContainer Root
            {
                get { return GetRoot(Context); }
            }

            public override IUnityContainer Session
            {
                get { return GetSession(Context); }
            }

            public override IUnityContainer Request
            {
                get { return GetRequest(Context); }
            }

            private IUnityContainer GetRequest(HttpContextBase ctx)
            {
                if (ctx.Items == null)
                {
                    return CreateRequest();
                }
                var request = ctx.Items[CACHEKEY_REQUSET_CONTAINER] as IUnityContainer;
                if (request != null)
                    return request;
                ctx.Items[CACHEKEY_REQUSET_CONTAINER] = request = CreateRequest();
                return request;
            }

            private IUnityContainer GetSession(HttpContextBase ctx)
            {
                if (ctx.Session == null)
                {
                    return CreateSession();
                }
                var container = ctx.Session[CACHEKEY_SESSION_CONTAINER] as IUnityContainer;
                if (container != null)
                    return container;
                ctx.Session[CACHEKEY_SESSION_CONTAINER] = container = CreateSession();
                return container;
            }

            private IUnityContainer GetRoot(HttpContextBase ctx)
            {
                var container = ctx.Application[CACHEKEY_SYSTEM_CONTAINER] as IUnityContainer;
                if (container != null)
                    return container;
                ctx.Application.Lock();
                try
                {
                    if ((container = ctx.Application[CACHEKEY_SYSTEM_CONTAINER] as IUnityContainer) == null)
                        ctx.Application[CACHEKEY_SYSTEM_CONTAINER] = container = CreateRoot();
                }
                finally
                {
                    ctx.Application.UnLock();
                }
                return container;
            }
        }

        #endregion

        #region IDisposable 成员

        /// <summary>
        /// 销毁
        /// <para>by tangjingbo at 2009-11-4 14:38</para>
        /// </summary>
        public void Dispose()
        {
            if (Root != null)
            {
                Root.Dispose();
            }
            GC.SuppressFinalize(this);
        }

        #endregion

        #region Nested type: LateBindConfiguration

        private class LateBindConfiguration : IContainerListener
        {
            #region IContainerListener Members

            public void CreateSystemContainer(AopContext ctx, IUnityContainer system)
            {
                ServiceManager.RootMap.Configure(system);
            }

            public void CreateSessionContainer(AopContext ctx, IUnityContainer session)
            {
                ServiceManager.SessionMap.Configure(session);
            }

            public void CreateRequestContainer(AopContext ctx, IUnityContainer request)
            {
                ServiceManager.RequsetMap.Configure(request);
            }

            #endregion
        }

        #endregion
    }

    /// <summary>
    /// 容器创建监听接口
    /// <para>2010/12/29</para>
    /// 	<para>TANGJINGBO</para>
    /// 	<para>tangjingbo</para>
    /// </summary>
    public interface IContainerListener
    {
        /// <summary>
        /// 系统级别容器创建
        /// </summary>
        /// <param name="ctx">The CTX.</param>
        /// <param name="system">The system.</param>
        void CreateSystemContainer(AopContext ctx, IUnityContainer system);

        /// <summary>
        /// 会话级别容器创建
        /// </summary>
        /// <param name="ctx">The CTX.</param>
        /// <param name="session">The session.</param>
        void CreateSessionContainer(AopContext ctx, IUnityContainer session);

        /// <summary>
        /// 请求级别容器创建
        /// </summary>
        /// <param name="ctx">The CTX.</param>
        /// <param name="request">The request.</param>
        void CreateRequestContainer(AopContext ctx, IUnityContainer request);
    }
}
